#include "ThreadPool.h"
#include "../../Core/Application/Program.h"

using namespace skelepp::Core::Tasking;
using namespace skelepp::Core::Application;

ThreadPool::ThreadPool(uint32_t threads) {
	for (uint32_t i = 0; i < threads; i++) {
		Worker *worker = new Worker();
		_workers.push_back(worker);
	}
	
	pthread_mutex_init(&_lock, NULL);
	uint32_t result = pthread_create(&_worker, NULL, _distribute, this);
}

ThreadPool::~ThreadPool(void) {
	for (vector<Worker *>::iterator it = _workers.begin(); it != _workers.end(); ++it) {
		Worker *worker = *it;
		delete worker;
	}
}

void ThreadPool::distribute(void) {
	while (Program::get()->is_running()) {
		yield();

		if (_high_queue.size() > 0 && _workers.size() > 0) {
			for (vector<Worker *>::iterator it = _workers.begin(); it != _workers.end(); ++it) {
				Worker *worker = *it;
				if (!worker->is_busy()) {
					_Task *front = (_Task *)_high_queue.front();
					worker->perform(front);
					_high_queue.pop();
					break;
				}
				yield();
			}
			continue;
		}

		if (_normal_queue.size() > 0 && _workers.size() > 0) {
			for (vector<Worker *>::iterator it = _workers.begin(); it != _workers.end(); ++it) {
				Worker *worker = *it;
				if (!worker->is_busy()) {
					_Task *front = (_Task *)_normal_queue.front();
					worker->perform(front);
					_normal_queue.pop();
					break;
				}
				yield();
			}
			continue;
		}

		if (_low_queue.size() > 0 && _workers.size() > 0) {
			for (vector<Worker *>::iterator it = _workers.begin(); it != _workers.end(); ++it) {
				Worker *worker = *it;
				if (!worker->is_busy()) {
					_Task *front = (_Task *)_low_queue.front();
					worker->perform(front);
					_low_queue.pop();
					break;
				}
				yield();
			}
			continue;
		}
	}
	pthread_exit(NULL);
}

void ThreadPool::perform(_Task *task) {
	switch (task->get_priority()) {
	case High:
		_high_queue.push(task);
		break;
	case Normal:
		_normal_queue.push(task);
		break;
	case Low:
		_low_queue.push(task);
		break;
	}
}